﻿using Framework.Startup.Attributes;
using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Framework.Startup
{
	/// <summary>
	/// 启动模块
	/// </summary>
	/// <typeparam name="TStartupModule"></typeparam>
	public abstract class StartupModule<TStartupModule> : IStartupModule where TStartupModule : IStartupModule, new()
	{
		/// <summary>
		/// 启动器执行循序，从小到大的顺序执行
		/// </summary>
		public virtual int Order { get; set; } = 328;

		/// <summary>
		/// 程序启动器
		/// </summary>
		public StartupModule()
		{
			var startupType = this.GetType();

			if (startupType.FullName != typeof(TStartupModule).FullName)
			{
				throw new Exception($"当前实例类型 {startupType.FullName} 与 泛型传入类型 {typeof(TStartupModule).FullName} 不一致!");
			}
		}

		/// <summary>
		/// 配置服务
		/// </summary>
		/// <param name="webApplicationBuilder"></param>
		public virtual void ConfigureServices(WebApplicationBuilder webApplicationBuilder)
		{

		}

		/// <summary>
		/// 配置
		/// </summary>
		/// <param name="webApplication"></param>
		public virtual void Configure(WebApplication webApplication)
		{

		}

		/// <summary>
		/// 程序启动 可以获取程序启动 urls
		/// </summary>
		/// <param name="webApplication"></param>
		public virtual void ApplicationStarted(WebApplication webApplication)
		{

		}

		/// <summary>
		/// 程序停止中
		/// </summary>
		/// <param name="webApplication"></param>
		public virtual void ApplicationStopping(WebApplication webApplication)
		{

		}

		/// <summary>
		/// 程序已经停止
		/// </summary>
		/// <param name="webApplication"></param>
		public virtual void ApplicationStopped(WebApplication webApplication)
		{

		}

		/// <summary>
		/// 获取所有导入的启动器实例
		/// </summary>
		/// <returns></returns>
		public List<IStartupModule> GetAllImportStartup()
		{
			var startupType = this.GetType();

			CheckLoopImportStartup(startupType);

			var importStartupAttributes = startupType.GetCustomAttributes<DependsOnAttribute>();

			var startups = new List<IStartupModule>();
			startups.Add(this);

			foreach (var item in importStartupAttributes)
			{
				FindImportStartup(startups, item);
			}

			foreach (var item in startups)
			{
				if (startups.Count(w => w.GetType().FullName == item.GetType().FullName) > 1)
				{
					startups.RemoveAt(startups.IndexOf(item));
				}
			}

			return startups.OrderBy(w => w.Order).ToList();
		}

		#region 私有

		/// <summary>
		/// 查找导入启动器特性
		/// </summary>
		/// <param name="startups"></param>
		/// <param name="importStartupAttribute"></param>
		private void FindImportStartup(List<IStartupModule> startups, DependsOnAttribute importStartupAttribute)
		{
			foreach (var startup in importStartupAttribute.GetStartups())
			{
				if (startups.Any(w => w.GetType().FullName == startup.GetType().FullName)) continue;

				startups.Add(startup);
			}

			// 循环启动器类型
			foreach (var startupType in importStartupAttribute.GetStartupTypes())
			{
				CheckLoopImportStartup(startupType);

				// 循环类型上的启动器标记
				var importStartupAttributes = startupType.GetCustomAttributes<DependsOnAttribute>();

				foreach (var item in importStartupAttributes)
				{
					FindImportStartup(startups, item);
				}
			}
		}

		/// <summary>
		/// 验证循环导入启动器类型
		/// </summary>
		/// <param name="startupType"></param>
		private void CheckLoopImportStartup(Type startupType)
		{
			// 循环类型上的启动器标记
			var importStartupAttributes = startupType.GetCustomAttributes<DependsOnAttribute>();

			foreach (var item in importStartupAttributes)
			{
				// 验证启动器类型 是否被循环导入了 ImportStartupAttribute 中
				if (item.GetStartupTypes().Any(w => w.FullName == startupType.FullName))
				{
					throw new Exception($"错误的导入。类型 {startupType.FullName} 特性标记 [ImportStartup] 不允许导入自身 {startupType.FullName} 启动器类型！");
				}
			}
		}

		#endregion
	}
}
